package com.system.core.interceptor.jwt;

import java.lang.reflect.Method;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import com.system.core.message.GenericException;
import com.system.core.security.jwt.JwtService;
import com.system.core.security.jwt.annotation.JwtTokenNeed;
import com.system.core.security.jwt.annotation.JwtTokenPass;
import com.system.core.security.jwt.dto.UserJWT;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

@Component
public class AuthenticationInterceptor implements HandlerInterceptor {

    @Autowired
    private JwtService jwtService;

    @Autowired
    private JwtConfigProperties jwtConfigProperties;

    @Autowired
    private JwtTokenStoreStrategy<UserJWT> jwtTokenStoreStrategy;

    @Autowired(required = false)
    private JwtAuthenticationInterceptorHook jwtAuthenticationInterceptorHook;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 如果不是映射到方法直接通过
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }

        //检查是否有passToken注释，有则跳过认证
        Method method = ((HandlerMethod) handler).getMethod();
        if (method.isAnnotationPresent(JwtTokenPass.class)) {
            JwtTokenPass passToken = method.getAnnotation(JwtTokenPass.class);
            if (passToken.required()) {
                return true;
            }
        }

        //检查是否有needToken注释，有则进入校验
        if (method.isAnnotationPresent(JwtTokenNeed.class)) {
            JwtTokenNeed jwtTokenNeed = method.getAnnotation(JwtTokenNeed.class);
            //获取到Token(优先从Header中获取，如果Header中取出来的值是空的，则尝试从参数表单中获取)
            String token = null;
            if (jwtConfigProperties.getHeader() != null) {
                token = request.getHeader(jwtConfigProperties.getHeader());
                if (StringUtils.isBlank(token)) {
                    token = request.getParameter(jwtConfigProperties.getHeader());
                }
            }

            //执行认证
            if (token == null && !jwtTokenNeed.required()) {
                return true;
            }
            if (token == null) {
                throw new GenericException(GenericException.APP_LOGOUT_CODE, "无token，请重新登录");
            }

            //解析Token
            UserJWT userInfo = jwtService.verifyToken(token, jwtTokenStoreStrategy.getUserJwtClass());
            if (!jwtTokenNeed.required()) {
                return true;
            }
            if (userInfo == null) {
                throw new GenericException(GenericException.APP_LOGOUT_CODE, "token无效，请重新登录");
            }

            if (userInfo != null && !jwtTokenNeed.tokenVerifyOnly()) {
                //校验Token是否仍在有效期
                String redisToken = jwtTokenStoreStrategy.get(userInfo, jwtTokenNeed.tokenType());
                if (StringUtils.isBlank(redisToken)) {
                    throw new GenericException(GenericException.APP_LOGOUT_CODE, "token已过期，请重新登录");
                } else {
                    if (!token.equals(redisToken)) {
                        throw new GenericException(GenericException.APP_LOGOUT_CODE, "该账号已在其它设备上登录，请重新登录");
                    }
                }
            }

            //验证完成后，调用勾子函数
            if (jwtAuthenticationInterceptorHook != null) {
                jwtAuthenticationInterceptorHook.invoke(jwtTokenNeed, userInfo, method, request);
            }

            request.getSession().setAttribute(UserJWT.USERINFOKEY, userInfo);
            return true;
        }
        return true;
    }
}
